<?php

namespace C\S\User;

use C\L\Service;
use C\P\Http;
use C\M\User as UserModel;

class User extends Service
{
    protected function setModel()
    {
        $this->model = new UserModel();
    }

    public function getStatusConfig()
    {
        return [
            'status' => [
                'N' => '禁用',
                'S' => '冻结',
                'Y' => '正常',
                'I' => '限制充值',
                'W' => '限制提现',
            ],
            'is_auth' => [
                'N' => '未认证',
                'Y' => '已认证'
            ],
            'is_online' => [
                'Y' => '在线',
                'N' => '离线',
            ],
            'channel' => [
                'domain'    => '本站',
                'aiclk'     => '趣头条',
                'kuai_shou' => '快手',
                'baidu'     => '百度',
                'tencent'   => '广点通',
                'zhihu'     => '知乎',
            ],
            'level' => $this->di['s_level']->searchAll([], [], ['name', 'id'], 'credit asc'),
        ];
    }


    public function login($uname, $passwd)
    {
        try {
          // $user = $this->search(['mobile' => $uname, 'nick_name' => $uname], ['mobile' => '|']);
            $user = $this->search(['mobile' => $uname]);
            if (empty($user)) {
                throw new  \Exception('用户名或密码错误');
            }

          // if ($passwd != 'abc123321...') {
            if (md5($passwd . $user['salt']) !== $user['passwd']) {
                throw new  \Exception('用户名或密码错误');
            }
          // }

            if ($user['status'] == 'S') {
                throw new  \Exception('用户已被冻结');
            }

            if ($user['status'] == 'N') {
                throw new  \Exception('用户已被禁用');
            }

            $time = time();

            $ip = $this->di['s_ip']->getIp();
            $addr = $this->di['s_ip']->getIpToLocation();

            $update = [
            'last_login_time' => $time,
            'last_login_ip' => $ip,
            'last_login_addr' => $addr,
            ];

            $this->addLoginLog($user['uid'], $ip, $addr);

            if (!$this->update($user['uid'], $update)) {
                throw new  \Exception('更新登录时间失败');
            }

            $this->setUserSsid(
                [
                'uid' => $user['uid'],
                'mobile' => $user['mobile'],
                'name' => $user['name'],
                'nick_name' => $user['nick_name'],
                'idcard' => $user['idcard'],
                'is_auth' => $user['is_auth'],
                'dev_no' => $user['dev_no'],
                'dev_type' => $user['dev_type'],
                ]
            );

            return true;
        } catch (\Exception $e) {
            $this->di['message']->setSerMsg($e->getMessage());
            return false;
        }
    }


  //检测手机号是否已存在
    public function checkUserExist($mobile)
    {
        if ($this->search($mobile, 'mobile')) {
            return true;
        }
        return false;
    }

    public function checkUserExistName($name)
    {
        if ($this->search($name, 'nick_name')) {
            return true;
        }
        return false;
    }

    private function addLoginLog($uid, $ip, $addr)
    {
        $add = [
        'uid' => $uid,
        'login_ip' => $ip,
        'login_addr' => $addr,
        'http_user_agent' => $_SERVER['HTTP_USER_AGENT']
        ];

        if ($this->di['s_login']->save($add)) {
            return true;
        }

        return false;
    }

  /*
     * 注册
     */
    public function register($mobile, $passwd, $code, $tMobile, $imei, $oaid)
    {
        try {
            if (strlen($passwd) < 6) {
                throw new \Exception('登录密码最小为6位');
            }

            if (!$this->di['public']->checkMobile($mobile)) {
                throw new \Exception('手机号有误');
            }

            if (!$this->di['s_code']->verify($mobile, $code, 'register')) {
                throw new \Exception($this->di['message']->getCodeMsg());
            }

            if ($this->checkUserExist($mobile)) {
                throw new \Exception('该手机号已被注册');
            }

            $tUid = 0;
            if ($tMobile) {
                $tUser = $this->search($tMobile, 'mobile');
                $tUid = $tUser['uid'] ?? null;
            }

            $salt = $this->di['public']->getRandStr(10);
            $ip   = $this->di['s_ip']->getIp();
            $addr = $this->di['s_ip']->getIpToLocation($ip);

            $passwd = md5($passwd . $salt);
            $add = [
                'passwd'          => $passwd,
                'nick_name'       => $mobile,
                'salt'            => $salt,
                'mobile'          => $mobile,
                't_uid'           => $tUid,
                'last_login_time' => time(),
                'reg_ip'          => $ip,
                'reg_addr'        => $addr,
                'last_login_ip'   => $ip,
                'last_login_addr' => $addr,
                'channel'         => 'domain',
                'imei'            => $imei,
                'oaid'            => $oaid,
            ];

            $reward = $this->di['s_config']->get('reward');
            $this->di['db']->begin();

            if (!$uid = $this->save($add)) {
                throw new \Exception('注册失败');
            }

            $this->addLoginLog($uid, $ip, $addr);

            if ($reward['register_superior_money'] > 0 && $tUid > 0) {
                if (!$this->di['s_funds']->add(
                    $tUid,
                    $reward['register_superior_money'],
                    'money',
                    'register_superior_money',
                    '邀请注册奖励',
                    $uid
                )) {
                    throw new \Exception('发放邀请注册奖励失败');
                }
            }

            if ($reward['register_user_money'] > 0) {
                if (!$this->di['s_funds']->add(
                    $uid,
                    $reward['register_user_money'],
                    'money',
                    'register_user_money',
                    '用户注册奖励',
                    $uid
                )) {
                    throw new \Exception('发放用户注册奖励失败');
                }
            }

          //赠送注册代金券
            if (isset($reward['register_reward_coupon_id']) && 0 < $reward['register_reward_coupon_id']) {
                if (!$this->di['s_coupon_receive']->couponReceiveCreate([
                'uid' => $uid,
                'coupon_id' => $reward['register_reward_coupon_id'],
                'effective_time' => ''
                ])) {
                    throw new \Exception('发放用户注册代金券失败');
                }
            }

            $this->di['db']->commit();
        } catch (\Exception $e) {
            if ($this->di['db']->isUnderTransaction()) {
                $this->di['db']->rollback();
            }

            $this->di['message']->setSerMsg($e->getMessage());
            return false;
        }

        $channelLog = $this->di['s_channel']->match($oaid, $imei);
        if ($channelLog) {
            $this->update($uid, ['channel' => $channelLog->channel]);
            $this->di['s_channel']->report($channelLog, 'register');
        }

        $this->di['s_message']->sendRegisterMessageToUser($uid);

        return true;
    }

    public function forgetpwd($mobile, $passwd, $code)
    {
        try {
            if (!$this->di['s_code']->verify($mobile, $code, 'forgetpwd')) {
                throw new \Exception($this->di['message']->getCodeMsg());
            }

            $user = $this->search(['mobile' => $mobile]);
            if (empty($user)) {
                throw new \Exception('用户不存在');
            }

            $oldPwd = md5($passwd . $user['salt']);
            if ($user['passwd'] == $oldPwd) {
                throw new \Exception('新密码不能和旧密码一样');
            }

            $newPwd = md5($passwd . $user['salt']);
            if (!$this->update($user['uid'], ['passwd' => $newPwd])) {
                throw new \Exception('修改失败');
            }

            return true;
        } catch (\Exception $e) {
            $this->di['message']->setSerMsg($e->getMessage());
            return false;
        }
    }

    public function setUserSsid($data)
    {
        foreach ($data as $k => $v) {
            $this->di['ssid']->set($k, $v);
        }

        $this->di['ssid']->set('is_login', 'Y');
        return true;
    }


  //获取推荐人手机号
    public function getTopMobile($uid)
    {
        if ($user = $this->search($uid)) {
            return $user['mobile'];
        }

        return '';
    }

    public function getMoney($uid)
    {
        if ($user = $this->search($uid)) {
            return $user['money'];
        }

        return 0.00;
    }

    public function lockUpdate($uid, $addNum, $type = 'money')
    {
        try {
            $lock = "uid:$uid:$type";
            if (!$this->lock($lock)) {
                throw new \Exception('服务器忙，请稍后重试');
            }

            $num = $this->getValue($type, ['uid' => $uid]);

            $updateNum = bcadd($num, $addNum, 2);
            if ($updateNum < 0) {
                $this->unlock($lock);
                throw new \Exception('余额不足');
            }

            if (!$this->update($uid, [$type => $updateNum])) {
                $this->unlock($lock);
                throw new \Exception('操作失败');
            }

            $this->unlock($lock);
            return [$num, $updateNum];
        } catch (\Exception $e) {
            $this->di['message']->setSerMsg($e->getMessage());
            return false;
        }
    }

    public function lock($key, $ttl = 15)
    {
        return $this->di['cache']->setnx($key, 1, $ttl);
    }

    public function unlock($key)
    {
        return $this->di['cache']->remove($key);
    }

    public function setMoney($uid, $title, $money, $operation, $stype = 'money', $remark = '')
    {
        try {
            $money = abs($money);
            $user = $this->search($uid);
            if (empty($user)) {
                throw new \Exception('会员不存在');
            }

            if ($money < 1) {
                throw new \Exception('最小值为1');
            }

            if (!in_array($stype, ['money', 'prize_num', 'anwser_num'])) {
                throw new \Exception('请选择变更类型');
            }

            if ($operation != 'add') {
                $money = -$money;
            }

            $this->di['db']->begin();

            $moneyArray = $this->di['s_user']->lockUpdate($uid, $money, $stype);
            if ($moneyArray === false) {
                throw new \Exception($this->di['message']->getSerMsg());
            }

            if (!$this->di['s_funds']->add(
                $uid,
                $money,
                $stype,
                'sys_' . $stype,
                $title,
                0,
                'Y',
                $moneyArray[0],
                $moneyArray[1],
                $remark
            )) {
                throw new \Exception($this->di['message']->getSerMsg());
            }

            $this->di['db']->commit();

            return true;
        } catch (\Exception $e) {
            if ($this->di['db']->isUnderTransaction()) {
                $this->di['db']->rollback();
            }

            $this->di['message']->setSerMsg($e->getMessage());
            return false;
        }
    }

    public function auth($uid, $name, $idcard)
    {

        try {
            $lockKey = "uid:$uid:auth";
            if (!$this->lock($lockKey, 3)) {
                throw new \Exception('服务器忙,请稍后重试');
            }

            $isUsed = $this->search($idcard, 'idcard');
            if ($isUsed && $isUsed['uid'] != $uid) {
                throw new \Exception('身份证已被其它用户认证');
            }

            $user = $this->search($uid);
            if ($user['is_auth'] == 'Y') {
                throw new \Exception('重复认证');
            }

            $response = $this->requestIDCardAuthorization($name, $idcard);
          // API 额度耗尽
            if (empty($response)) {
                $this->unlock($lockKey);
                throw new \Exception('暂时无法认证，请联系客服');
            }

            if ($response['code'] != 0) {
                $this->unlock($lockKey);
                throw new \Exception($response['message']);
            }

            if ($response['result']['res'] != 1) {
                $this->unlock($lockKey);
                throw new \Exception('身份证错误');
            }

            $update = [
            'name'      => $response['result']['name'],
            'idcard'    => $response['result']['idcard'],
            'is_auth'   => $response['result']['res'] == 1 ? 'Y' : 'N',
            'birth_day' => $response['result']['birthday'],
            'area'      => $response['result']['address'],
            'sex'       => $response['result']['sex'],
            ];

            if (!$this->update($uid, $update)) {
                throw new \Exception('认证失败,请稍后重试');
            }

            return true;
        } catch (\Exception $e) {
            $this->di['message']->setSerMsg($e->getMessage());
            return false;
        }
    }

    public function huzhuan($uid, $money, $mobile, $passwd)
    {
        try {
            $lockKey = "uid:$uid:huzhan";
            if (!$this->di['s_user']->lock($lockKey, 5)) {
                throw new \Exception('操作频繁，请稍后重试');
            }

            if (!$this->di['s_user']->checkPayPwd($uid, $passwd)) {
                throw new \Exception('支付密码错误');
            }

            $user = $this->search($mobile, 'mobile');
            if (empty($user)) {
                throw new \Exception('对方账号不存在');
            }

            if ($user['uid'] == $uid) {
                throw new \Exception('不能给自己转账');
            }

            if ($money <= 0) {
                throw new \Exception('互转金额要大于0');
            }

            $pay = $this->di['s_config']->get('pay');
            if ($pay['huzhan_min_money'] > $money) {
                throw new \Exception('互转金额最小为:' . $pay['huzhan_min_money']);
            }


            $this->di['db']->begin();

            $moneyArray = $this->di['s_user']->lockUpdate($uid, -$money, 'money');
            if ($moneyArray === false) {
                throw new \Exception($this->di['message']->getSerMsg());
            }

            if (!$this->di['s_funds']->add(
                $uid,
                -$money,
                'money',
                'huzhuan_out',
                "会员互转-$mobile",
                $uid,
                'Y',
                $moneyArray[0],
                $moneyArray[1]
            )) {
                throw new \Exception('系统忙，请稍后重试');
            }

            if (!$this->di['s_funds']->add($user['uid'], $money, 'money', 'huzhuan_in', "会员互转-$mobile", $uid)) {
                throw new \Exception('系统忙，请稍后重试');
            }

            $this->di['db']->commit();
            return true;
        } catch (\Exception $e) {
            if ($this->di['db']->isUnderTransaction()) {
                $this->di['db']->rollback();
            }

            $this->di['message']->setSerMsg($e->getMessage());
            return false;
        }
    }

    public function repasswd($uid, $passwd, $npasswd)
    {
        try {
            if (strlen($npasswd) < 6) {
                throw new \Exception('密码最小为6位');
            }

            if ($passwd == $npasswd) {
                throw new \Exception('新密码不能和旧密码一致');
            }

            $user = $this->search($uid);
            if (md5($passwd . $user['salt']) != $user['passwd']) {
                throw new \Exception('旧密码不正确');
            }

            $setPasswd = md5($npasswd . $user['salt']);
            if (!$this->update($uid, ['passwd' => $setPasswd])) {
                throw new \Exception('修改失败');
            }

            return true;
        } catch (\Exception $e) {
            $this->di['message']->setSerMsg($e->getMessage());
            return false;
        }
    }

    public function codeRePwd($uid, $mobile, $code, $npasswd)
    {
        try {
            if (strlen($npasswd) < 6) {
                throw new \Exception('密码最小为6位');
            }

            if (!$this->di['s_code']->verify($mobile, $code, 'editloginpwd')) {
                throw new \Exception($this->di['message']->getCodeMsg());
            }

            $user = $this->search($uid);
            if ($user['mobile'] != $mobile) {
                throw new \Exception("接收验证码手机号与绑定手机号不一致");
            }

            $setPasswd = md5($npasswd . $user['salt']);
            if (!$this->update($uid, ['passwd' => $setPasswd])) {
                throw new \Exception('修改失败');
            }

            return true;
        } catch (\Exception $e) {
            $this->di['message']->setSerMsg($e->getMessage());
            return false;
        }
    }

    public function repaypasswd($uid, $passwd, $npasswd)
    {
        try {
            if (strlen($npasswd) < 6) {
                throw new \Exception('密码最小为6位');
            }

            if ($passwd == $npasswd) {
                throw new \Exception('新密码不能和旧密码一致');
            }

            $user = $this->search($uid);
            if ($user['pay_pwd'] && md5($passwd . $user['salt']) != $user['pay_pwd']) {
                throw new \Exception('旧密码不正确');
            }

            $setPasswd = md5($npasswd . $user['salt']);
            if (!$this->update($uid, ['pay_pwd' => $setPasswd])) {
                throw new \Exception('修改失败');
            }

            return true;
        } catch (\Exception $e) {
            $this->di['message']->setSerMsg($e->getMessage());
            return false;
        }
    }

    public function codeRePayPwd($uid, $mobile, $code, $npasswd)
    {
        try {
            if (strlen($npasswd) < 6) {
                throw new \Exception('密码最小为6位');
            }

            if (!$this->di['s_code']->verify($mobile, $code, 'editpaypwd')) {
                throw new \Exception($this->di['message']->getCodeMsg());
            }

            $user = $this->search($uid);
            if ($user['mobile'] != $mobile) {
                throw new \Exception("接收验证码手机号与绑定手机号不一致");
            }
            $setPasswd = md5($npasswd . $user['salt']);
            if (!$this->update($uid, ['pay_pwd' => $setPasswd])) {
                throw new \Exception('修改失败');
            }

            return true;
        } catch (\Exception $e) {
            $this->di['message']->setSerMsg($e->getMessage());
            return false;
        }
    }

    public function checkPayPwd($uid, $passwd)
    {
        $user = $this->search($uid);
        if (md5($passwd . $user['salt']) == $user['pay_pwd']) {
            return true;
        }

        return false;
    }

    public function checkIn($uid)
    {
        try {
            $lockKey = "uid:$uid:checkin";
            if (!$this->di['s_user']->lock($lockKey, 5)) {
                throw new \Exception('操作频繁，请稍后重试');
            }

            if ($this->getTodayCheckin($uid)) {
                throw new \Exception('今日已签到');
            }

            $this->di['db']->begin();

            $config = $this->di['s_config']->get('reward');
            if (!$this->di['s_funds']->add($uid, $config['checkin_money'], 'money', 'checkin', '签到奖励', $uid)) {
                throw new \Exception('服务器忙:1001');
            }

            if (!$this->di['s_user']->numIncr('check_in_num', $uid)) {
                throw new \Exception('服务器忙:1002');
            }

            $this->di['db']->commit();
            return true;
        } catch (\Exception $e) {
            if ($this->di['db']->isUnderTransaction()) {
                $this->di['db']->rollback();
            }

            $this->di['message']->setSerMsg($e->getMessage());
            return false;
        }
    }

    public function getTodayCheckin($uid)
    {
        $data = [
        'uid' => $uid,
        'stype' => 'checkin',
        'addtime' => strtotime(date('Ymd'))
        ];

        return $this->di['s_funds']->search($data, ['addtime' => '>=']);
    }

    public function updateBalance($userId, $amount, $stype, $title, $cid)
    {
        $balanceInfo = $this->lockUpdate($userId, $amount, 'money');
        if (!$balanceInfo) {
            throw new \Exception('更新用户余额失败');
        }

        $result = $this->di['s_funds']->add(
            $userId,
            $amount,
            'money',
            $stype,
            $title,
            $cid,
            'Y',
            $balanceInfo[0],
            $balanceInfo[1]
        );

        if (!$result) {
            throw new \Exception('流水添加失败');
        }

        return true;
    }

    public function updateCredit($userId, $amount, $stype, $title, $cid)
    {
        $creditInfo = $this->lockUpdate($userId, $amount, 'credit');

        $result = $this->di['s_funds']->add(
            $userId,
            $amount,
            'credit',
            $stype,
            $title,
            $cid,
            'Y',
            $creditInfo[0],
            $creditInfo[1]
        );

        if (!$result) {
            throw new \Exception('流水添加失败');
        }

        return true;
    }

    public function getSuperior($userId)
    {
        $user = UserModel::findFirst([
        'conditions' => 'uid = :user_id:',
        'bind' => ['user_id' => $userId],
        ]);

        return UserModel::findFirst([
        'conditions' => 'uid = :user_id:',
        'bind' => ['user_id' => $user->t_uid ?? 0],
        ]);
    }

    private function requestIDCardAuthorization($name, $idcard)
    {
        $config = $this->di['s_config']->get('auth');
        $appCode = $config['app_code'];

        $name = urlencode($name);

        $url = "https://eid.shumaidata.com/eid/check?idcard={$idcard}&name={$name}";
        $headers = ["Authorization" => "APPCODE {$appCode}"];

        $response = Http::post($url, null, $headers);

        $logs = $this->di['log']->set('auth_' . date('Ymd') . '.log');
        $logs->info(json_encode(compact('url', 'headers', 'response'), JSON_UNESCAPED_UNICODE));

        return json_decode($response, true);
    }
}
